package com.qg.base.utils;

import cn.hutool.core.date.StopWatch;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;

/**
 * 文件下载工具类
 */
public class FileDownUtil {

    public static void main(String[] args) throws InterruptedException {
        String url = "http://qiegao.xyz:9000/xuecheng-vedio/5/4/54c19d47fea6f127e9d79ba3198750a0/54c19d47fea6f127e9d79ba3198750a0.mp4";
        String url2 = "https://download.jetbrains.com/idea/ideaIU-2023.2.exe";
        String destFilePath = "F://test/" + url2.substring(url2.lastIndexOf("/") + 1);
        //需要使用CountDownLatch来计时，因为使用的多线程进行下载
        FileDownUtil.download(url2, destFilePath);
    }

    //文件下载线程数
    private final static int DEFAULT_THREAD_SIZE = 5;


    /**
     * 下载文件的方法（内部通过RandomAccessFile实现多线程下载文件）
     *
     * @param url          下载链接
     * @param destLocation 目标下载地址
     */
    public static void download(String url, String destLocation) throws InterruptedException {
        StopWatch stopWatch = new StopWatch("uploadFile" + url);
        stopWatch.start();
        File dest = new File(destLocation);
        int fileSize = computeFileSize(url);
        if (fileSize <= 0) {
            throw new RuntimeException("读取文件失败");
        }
        int singleSize = fileSize / DEFAULT_THREAD_SIZE;
        CountDownLatch countDownLatch = new CountDownLatch(singleSize);

        for (int i = 0; i < DEFAULT_THREAD_SIZE; i++) {
            int startIndex = i * singleSize;
            int endIndex = (i + 1) * singleSize;
            if (i == DEFAULT_THREAD_SIZE - 1) {
                endIndex = fileSize;
            }
            new DownloadThread(url, dest, startIndex, endIndex,countDownLatch).start();
        }

        countDownLatch.await();
        stopWatch.stop();
        System.out.println("文件下载成功 耗时 ==》" + stopWatch.getTotalTimeSeconds() + "秒");
    }

    /**
     * 计算需要下载的文件大小
     *
     * @param url 下载链接
     * @return 文件大小
     */
    private static int computeFileSize(String url) {
        try {
            URL address = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) address.openConnection();
            if (connection.getResponseCode() == 200) {
                return connection.getContentLength();
            }
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }


    static class DownloadThread extends Thread {

        private String url;
        private File destFile;
        private int startIndex;
        private int endIndex;

        private CountDownLatch countDownLatch;

        DownloadThread(String url, File destFile, int startIndex, int endIndex, CountDownLatch countDownLatch) {
            super();
            this.url = url;
            this.destFile = destFile;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                URL address = new URL(url);
                HttpURLConnection connection = (HttpURLConnection) address.openConnection();
                //设置请求参数
                connection.setRequestProperty("User-Agent", "NetFox");
                connection.setRequestProperty("RANGE", "bytes=" + startIndex + "-" + endIndex);
                connection.connect();
                //写文件
                RandomAccessFile raFile = new RandomAccessFile(destFile, "rw");
                raFile.seek(startIndex);

                InputStream inputStream = connection.getInputStream();
                BufferedInputStream bis = new BufferedInputStream(inputStream);
                int len = 0;
                byte[] b = new byte[2048];
                while ((len = bis.read(b)) != -1) {
                    raFile.write(b, 0, len);
                }
                bis.close();
                raFile.close();
                connection.disconnect();
                countDownLatch.countDown();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

    }
}
